package com.cn.shiro_jwt_redis.controller;

import com.cn.shiro_jwt_redis.comm.model.ResultData;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 张坤鹏
 * @Date: 2021/08/06/14:22
 * @Description:
 */
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    /**
     * 捕获所有的shiro异常
     * @param e
     * @return resultData
     */
    @ExceptionHandler(ShiroException.class)
    public ResultData handle401(ShiroException e){
        return new ResultData().code(401)
                .message("无权访问(Unauthorized):"+e.getMessage());
    }

    /**
     * 单独捕获shiro(UnauthorizedException)异常
     * 该异常用户发送请求时   用户权限不足时抛出的异常
     * @param e
     * @return resultData
     */
    @ExceptionHandler(UnauthorizedException.class)
    public ResultData handle401(UnauthorizedException e){
        return new ResultData().code(401)
                .message("无权访问(Unauthorized):当前Subject没有此请求所需权限("+e.getMessage()+")");
    }

    /**
     * 单独捕获shiro(UnauthenticatedException)异常
     * 该异常为以游客身份访问有权限管控的请求  无法对匿名主体进行授权 授权失败的异常
     * @param e
     * @return resultData
     */
    @ExceptionHandler(UnauthenticatedException.class)
    public ResultData handle401(UnauthenticatedException e){
        return new ResultData().code(401)
                .message("无权访问(Unauthorized):当前Subject是匿名Subject，请先登录(This subject is anonymous.)");
    }

    /**
     * 捕获校检异常(BindException)
     * @param e
     * @return resultData
     */
    @ExceptionHandler(BindException.class)
    public ResultData validException(BindException e){
        List<FieldError> fieldErrors=e.getBindingResult().getFieldErrors();
        Map<String,Object> error=this.getValidError(fieldErrors);
        return new ResultData().code(400)
                .message(error.get("errorMsg").toString())
                .data(error.get("errorList"));
    }


    /**
     * 捕获404异常
     * @param e
     * @return resultData
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResultData handle(NoHandlerFoundException e){
        return new ResultData().code(404)
                .message(e.getMessage());
    }


    /**
     * 捕获其他所有异常
     * @param request
     * @param throwable
     * @return resuleData
     */
    @ExceptionHandler(Exception.class)
    public ResultData globalException(HttpServletRequest request,Throwable throwable){
        return new ResultData().code(500)
                .message(throwable.toString()+":"+throwable.getMessage());
    }



    /**
     * 获取状态码
     * @param request
     * @return httpStatues
     */
    private HttpStatus getStatus(HttpServletRequest request){
        Integer statusCode=(Integer)request.getAttribute("javax.servlet.error.status_code");
        if (statusCode==null){
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }

    /**
     * 获取校检错误信息
     * @param fieldErrors
     * @return map
     */
    private Map<String,Object> getValidError(List<FieldError> fieldErrors){
        Map<String,Object> map=new HashMap<>();
        List<String> errorList=new ArrayList<String>();
        StringBuffer errorMsg=new StringBuffer("校验异常(ValidException):");
        for (FieldError fieldError:fieldErrors) {
            errorList.add(fieldError.getField()+"-"+fieldError.getDefaultMessage());
            errorMsg.append(fieldError.getField()+"-"+fieldError.getDefaultMessage()+".");
        }
        map.put("errorList",errorList);
        map.put("errorMsg",errorMsg);
        return map;
    }
}
